package javaproject;

import com.sun.j3d.loaders.IncorrectFormatException;
import com.sun.j3d.loaders.ParsingErrorException;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.image.TextureLoader;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.net.MalformedURLException;
import java.util.Iterator;
import java.util.LinkedList;
import javax.media.j3d.Appearance;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.OrientedShape3D;
import javax.media.j3d.QuadArray;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Texture;
import javax.media.j3d.Texture2D;
import javax.media.j3d.TextureAttributes;
import javax.media.j3d.Transform3D;
import javax.media.j3d.TransformGroup;
import javax.media.j3d.TransparencyAttributes;
import javax.media.j3d.TriangleFanArray;
import javax.swing.Timer;
import javax.vecmath.Point3d;
import javax.vecmath.Point3f;
import javax.vecmath.TexCoord2f;
import javax.vecmath.Vector3d;

class Vic_Viper extends MyPrimitive{
    Vic_Viper(double x, double y, double z)
    {
        super(x,y,z,new Appearance());
        try{
            Transform3D transTemp = new Transform3D();
            transTemp.setScale(Config.vic_viperSize);
            Transform3D transTemp2 = new Transform3D();
            transTemp2.rotX(Math.PI/2);
            transTemp.mul(transTemp2);
            transTemp2.rotY(Math.PI/2);
            transTemp.mul(transTemp2);
            transTemp2.set(new Vector3d(x,y,z));
            transTemp.mul(transTemp2);

            DAELoader loader = new DAELoader();
            BranchGroup BG = loader.load("vic.dae").getSceneGroup();
            TransformGroup TG = (TransformGroup)BG.getChild(0);
            TG.setTransform(transTemp);
            shape = (Shape3D)((TransformGroup)TG.getChild(0)).getChild(0);
            BG.removeChild(TG);

	    //尾波
	    ShockWave tail = new ShockWave(0,-Config.vic_viperSize*0.95,-0.01);
	    tail.setSize(tail.disk, Config.vic_viperSize*0.5, 0.3f);
	    tail.setSize(tail.circle, 0.000001, 0.3f);
	    transG.addChild(tail.getTransformGroup());

            transG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
            transG.addChild(TG);
            translate = transTemp;
        }
        catch (FileNotFoundException e) {
            System.err.println(e);
            System.exit(1);
        }
        catch (ParsingErrorException e) {
            System.err.println(e);
            System.exit(1);
        }
        catch (IncorrectFormatException e) {
            System.err.println(e);
            System.exit(1);
        }

    }
}
class Option extends MyPrimitive{
    Option(double x, double y, double z, Appearance app)
    {
        super(x,y,z,app);

        transG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	transG.addChild(new Sphere(Config.optionSize, app));

        moveTo(x,y,z);
    }
}
class ShockWave extends MyPrimitive
{
    private double scale;
    private Timer extender;
    public OrientedShape3D circle;
    public OrientedShape3D disk;
    ShockWave(double x, double y, double z)
    {
	super(x,y,z,null);
	scale = 1;

	int circles = 64;    //段數
	int circleVertices = 4*circles;   //一片四點
	int diskVertices = circles+2;   //扇狀(+重複一點)+原點
	float radius = 0.49f;	//大環外圈
	float thickness = 0.01f;	//橫切面管半徑
	//相加等於0.5(半徑)，配合貼圖

	Point3d[] circleCoords = new Point3d[circleVertices];
	TexCoord2f[] circleTexCoords = new TexCoord2f[circleVertices];


	double u = 2*Math.PI/circles;
	for(int i = 0; i < circles; i++)
	{
	    //	   第幾邊		//第幾環
	    circleCoords[i*4] =   new Point3d((radius - thickness)*Math.cos(u*(i+1)), (radius - thickness)*Math.sin(u*(i+1)), 0);
	    circleCoords[i*4+1] = new Point3d((radius - thickness)*Math.cos(u*i),	    (radius - thickness)*Math.sin(u*i),	0);
	    circleCoords[i*4+2] = new Point3d((radius + thickness)*Math.cos(u*i),	    (radius + thickness)*Math.sin(u*i),	0);
	    circleCoords[i*4+3] = new Point3d((radius + thickness)*Math.cos(u*(i+1)), (radius + thickness)*Math.sin(u*(i+1)), 0);

	    circleTexCoords[i*4] = new TexCoord2f((float)((radius - thickness)*Math.cos(u*(i+1))) + (radius+thickness),   (float)((radius - thickness)*Math.sin(u*(i+1))) + (radius+thickness));
	    circleTexCoords[i*4+1] = new TexCoord2f((float)((radius - thickness)*Math.cos(u*i)) + (radius+thickness),	    (float)((radius - thickness)*Math.sin(u*i)) + (radius+thickness));
	    circleTexCoords[i*4+2] = new TexCoord2f((float)((radius + thickness)*Math.cos(u*i)) + (radius+thickness),	    (float)((radius + thickness)*Math.sin(u*i)) + (radius+thickness));
	    circleTexCoords[i*4+3] = new TexCoord2f((float)((radius + thickness)*Math.cos(u*(i+1))) + (radius+thickness), (float)((radius + thickness)*Math.sin(u*(i+1))) + (radius+thickness));
	}

	Point3d[] diskCoords = new Point3d[diskVertices];
	TexCoord2f[] diskTexCoords = new TexCoord2f[diskVertices];
	diskCoords[circles+1] = new Point3d(0,0,0);
	diskTexCoords[circles+1] = new TexCoord2f(0,0);
	for(int i = 0; i < circles+1; i++)
	{
	    diskCoords[i] = new Point3d((radius - thickness)*Math.cos(u*i),	    (radius - thickness)*Math.sin(u*i),	0);
	    diskTexCoords[i] = new TexCoord2f((float)((radius - thickness)*Math.cos(u*i)) + (radius+thickness),   (float)((radius - thickness)*Math.sin(u*i)) + (radius+thickness));
	}

	QuadArray qa = new QuadArray(circleVertices, QuadArray.COORDINATES | QuadArray.TEXTURE_COORDINATE_2);
	qa.setCoordinates(0, circleCoords);
	qa.setTextureCoordinates(0, 0, circleTexCoords);

	TriangleFanArray tfa = new TriangleFanArray(diskVertices, TriangleFanArray.COORDINATES | TriangleFanArray.TEXTURE_COORDINATE_2, new int[]{diskVertices});
	tfa.setCoordinates(0, diskCoords);
	tfa.setTextureCoordinates(0, 0, diskTexCoords);

	try
	{
	    TextureLoader circleLoader = new TextureLoader(new File("./img/explodeCircle1024.png").toURI().toURL(), null);
	    TextureLoader diskLoader = new TextureLoader(new File("./img/explodeDisk1024.png").toURI().toURL(), null);
	    Appearance appCircle = new Appearance();
	    Appearance appDisk = new Appearance();

	    Texture2D circleT = new Texture2D(Texture.BASE_LEVEL,Texture.RGBA, 1024, 1024);
	    circleT.setImage(0, circleLoader.getImage());
	    appCircle.setTexture(circleT);
	    
	    Texture2D diskT = new Texture2D(Texture.BASE_LEVEL,Texture.RGBA, 1024, 1024);
	    diskT.setImage(0, diskLoader.getImage());
	    appDisk.setTexture(diskT);

	    //以下兩共用
	    TransparencyAttributes appTrans = new TransparencyAttributes(TransparencyAttributes.BLENDED, 0.0f);
	    appTrans.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE);
	    appCircle.setTransparencyAttributes(appTrans);
	    appDisk.setTransparencyAttributes(appTrans);

	    TextureAttributes texAtt = new TextureAttributes();
	    texAtt.setTextureMode(TextureAttributes.MODULATE);//MODULATE
	    appCircle.setTextureAttributes(texAtt);
	    appDisk.setTextureAttributes(texAtt);

	    circle = new OrientedShape3D(new Shape3D(qa).getGeometry(), appCircle, OrientedShape3D.ROTATE_ABOUT_POINT, new Point3f( 0.0f, 0.0f, 0.0f ));
	    disk = new OrientedShape3D(new Shape3D(tfa).getGeometry(), appDisk, OrientedShape3D.ROTATE_ABOUT_POINT, new Point3f( 0.0f, 0.0f, 0.0f ));
	}
	catch (MalformedURLException e) {
	    throw new RuntimeException();
	}

	TransformGroup transCircle = new TransformGroup();
	TransformGroup transDisk = new TransformGroup();
	transCircle.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	transDisk.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	transCircle.addChild(circle);
	transDisk.addChild(disk);

	transG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	transG.addChild(transCircle);
	transG.addChild(transDisk);

	//動作Timer
	extender = new Timer(Config.refreshRate, new ActionListener()
	{
	    public void actionPerformed(ActionEvent e) {
		if(scale < 1)	//1為最大
		{
		    scale+=Config.extendStep;
		    setSize(circle, scale, (float)scale);
		    setSize(disk, (1-scale)*Config.areaFactor, (float)scale);
		}
		else
		    extender.stop();
	    }
	});
	extender.setRepeats(true);
    }
    public void setSize(OrientedShape3D target, double scale, float alpha)   //0 <= s <= 1
    {
	translate = new Transform3D();
	translate.setScale(scale);
	((TransformGroup)target.getParent()).setTransform(translate);
	target.getAppearance().getTransparencyAttributes().setTransparency(alpha);
    }
    public void start()
    {
	scale = Config.extendStep; //scale不可設為0，會出錯
	setSize(circle, scale, 0);
	setSize(disk, (1-scale)*Config.areaFactor, 0);
	extender.start();
    }
}
class Snake
{
    static final int NONE = 99;
    static final int UP = 1;
    static final int DOWN = -1;
    static final int LEFT = 2;
    static final int RIGHT = -2;
    static final int ASC = 3;
    static final int DESC = -3;
    static final int UP_RIGHT = 4;
    static final int UP_LEFT = -4;
    static final int DOWN_RIGHT = 5;
    static final int DOWN_LEFT = -5;

    public LinkedList<MyPrimitive> blocks = new LinkedList<MyPrimitive>(); //注意順序是反的，第一個是蛇的尾巴
    private Graph3D graph3D;
    private BranchGroup objSpin;
    private Debugger debugger;
    private ShockWave shockWave;
    private double vx;
    private double vy;
    private double vz;
    public int options;

    Snake(Graph3D graph3D, BranchGroup objSpin, Debugger debugger)
    {
	this.graph3D = graph3D;
	this.objSpin = objSpin;
	this.debugger = debugger;
	options = Config.initLength;
        for(int i = 1; i <= Config.maxLength; i++)
        {
            /*
            float alpha;
            if(i <= Config.initLength)
                alpha = 0;
            else
                alpha = 1;

	    //初始化
            Appearance app = new Appearance();
            app.setColoringAttributes(new ColoringAttributes(Config.optionColor, ColoringAttributes.NICEST));
	    TransparencyAttributes appTrans = new TransparencyAttributes(TransparencyAttributes.BLENDED, alpha);
	    appTrans.setCapability(TransparencyAttributes.ALLOW_VALUE_WRITE);
            app.setTransparencyAttributes(appTrans);


            Option o = new Option(0,Config.outOfScreen,0, app);
            objSpin.addChild(o.getTransformGroup());
            blocks.addFirst(o);  //順序反過來，以後比較方便移動
            * 
            */
        }
        //MODEL
        Vic_Viper vic_viper = new Vic_Viper(0,0,0);
        objSpin.addChild(vic_viper.getTransformGroup());
        blocks.addLast(vic_viper);
	//ShockWave
	shockWave = new ShockWave(0,0,0);
	shockWave.moveTo(Config.outOfScreen,0,0);
	objSpin.addChild(shockWave.getTransformGroup());
    }
    private void explode()
    {
	Vic_Viper first = (Vic_Viper)blocks.getLast();
	shockWave.moveTo(first.x, first.y, first.z);
	shockWave.start();
	SoundEX.play(SoundEX.EXPLODE);
	//if(!Config.debug)
	//{
	    first.moveTo(0, Config.outOfScreen, 0);
	    graph3D.gameOver();
	//}
    }
    /*
    public static int fixDirection(int dir, SpinGroup objSpin)
    {
	if(objSpin.radX == 0)
	{
	    if((objSpin.radZ >= 0 && objSpin.radZ < Math.PI/4) || (objSpin.radZ > Math.PI/4*7 && objSpin.radZ < 2*Math.PI))
	    {
		//沒有變換
	    }
	    else if(objSpin.radZ >= Math.PI/4 && objSpin.radZ < Math.PI/4*3)  //[PI/4,PI/4*3)
	    {
		switch(dir)
		{
		    case Snake.UP:
			dir = Snake.RIGHT;
			break;
		    case Snake.DOWN:
			dir = Snake.LEFT;
			break;
		    case Snake.LEFT:
			dir = Snake.UP;
			break;
		    case Snake.RIGHT:
			dir = Snake.DOWN;
			break;
		}
	    }
	    else if(objSpin.radZ >= Math.PI/4*3 && objSpin.radZ < Math.PI/4*5)  //[PI/4*3,PI/4*5)
	    {
		if(dir == Snake.UP || dir == Snake.DOWN || dir == Snake.LEFT || dir == Snake.RIGHT)
		    dir = -dir;
	    }
	    else if(objSpin.radZ >= Math.PI/4*5 && objSpin.radZ < Math.PI/4*7)  //[PI/4*5,PI/4*7)
	    {
		switch(dir)
		{
		    case Snake.UP:
			dir = Snake.LEFT;
			break;
		    case Snake.DOWN:
			dir = Snake.RIGHT;
			break;
		    case Snake.LEFT:
			dir = Snake.DOWN;
			break;
		    case Snake.RIGHT:
			dir = Snake.UP;
			break;
		}
	    }
	    return dir;
	}
	else	//radX == PI
	{
	    if(dir == Snake.ASC || dir == Snake.DESC)
		dir = -dir;
	    else if((objSpin.radZ >= 0 && objSpin.radZ < Math.PI/4) || (objSpin.radZ > Math.PI/4*7 && objSpin.radZ < 2*Math.PI))
	    {
		if(dir == Snake.UP || dir == Snake.DOWN)
		    dir = -dir;
	    }
	    else if(objSpin.radZ >= Math.PI/4 && objSpin.radZ < Math.PI/4*3)  //[PI/4,PI/2)
	    {
		switch(dir)
		{
		    case Snake.UP:
			dir = Snake.LEFT;
			break;
		    case Snake.DOWN:
			dir = Snake.RIGHT;
			break;
		    case Snake.LEFT:
			dir = Snake.UP;
			break;
		    case Snake.RIGHT:
			dir = Snake.DOWN;
			break;
		}
	    }
	    else if(objSpin.radZ >= Math.PI/4*3 && objSpin.radZ < Math.PI/4*5)  //[PI/4*3,PI/4*5)
	    {
		if(dir == Snake.LEFT || dir == Snake.RIGHT)
		    dir = -dir;
	    }
	    else if(objSpin.radZ >= Math.PI/4*5 && objSpin.radZ < Math.PI/4*7)  //[PI/4*5,PI/4*7)
	    {
		switch(dir)
		{
		    case Snake.UP:
			dir = Snake.RIGHT;
			break;
		    case Snake.DOWN:
			dir = Snake.LEFT;
			break;
		    case Snake.LEFT:
			dir = Snake.DOWN;
			break;
		    case Snake.RIGHT:
			dir = Snake.UP;
			break;
		}
	    }
	    return dir;
	}
    }
     * 
     */
    public void reduce()
    {
	if(options <= 0)    //已經沒有了還被撞到
	{
	    explode();
	}
	else
	{
	    SoundEX.play(SoundEX.HIT);
	    //Option o = (Option)blocks.get(Config.maxLength-options);
	    //o.getAppearance().getTransparencyAttributes().setTransparency(1);
	    options--;
	}
    }
    public void add()
    {
	//if(options+1 < blocks.size())
	//{
	    SoundEX.play(SoundEX.OPTION);
	    options++;
	//    Option o = (Option)blocks.get(Config.maxLength-options);
	//    o.getAppearance().getTransparencyAttributes().setTransparency(0);
	//}
    }
    public void cheat()
    {
	for(int i = 0; i < Config.maxLength; i++)
	    add();
    }
    public void setV(double vx, double vy, double vz)
    {
        this.vx = vx;
        this.vy = vy;
        this.vz = vz;
    }
    public void proceed(int direction, Bullets bullets, Capsules capsules, BlockWall wall)
    {
        MyPrimitive first = blocks.getLast(); //最後一個是頭

	if(checkBullet(first, bullets) != null)
	{
	    Bullet b = checkBullet(first, bullets);

            AI.hitBullet = true;  //讓AI知道撞到子彈了
	    b.randomize();  //被撞到後要把子彈移走

	    reduce();
	    if(Config.debug)
		System.out.println("Bullet!");
	}
	else if(checkCapsule(first, capsules) != null)
	{
	    Capsule c = checkCapsule(first, capsules);
	    c.randomize();  //被撞到後要把Capsule移走

	    add();
	    if(Config.debug)
		System.out.println("Capsule!");
	}
	else if(wall != null && checkWall(first, wall) == true)
	{
	    explode();
	    if(Config.debug)
		System.out.println("撞到牆");
	}
	else if(checkBounding(first) == true)
	{
	    explode();
	    if(Config.debug)
		System.out.println("撞到外框");
	}
	Iterator it = blocks.iterator();
	if(it.hasNext())    //除了第一個，將每一個block往前移動
	{
	    MyPrimitive now = (MyPrimitive)it.next();   //從尾巴開始
	    while(it.hasNext())
	    {
		MyPrimitive next = (MyPrimitive)it.next();
                if(next.equals(first))
                    now.moveTo(next.x - Config.threshold*(next.x-now.x), next.y - Config.threshold*(next.y-now.y)-Config.gap, next.z - Config.threshold*(next.z-now.z));
//                    now.moveTo(next.x - Config.threshold*(next.x-now.x), next.y - Config.threshold*(next.y-now.y), next.z - Config.threshold*(next.z-now.z));
                else
                    now.moveTo(next.x - Config.threshold*(next.x-now.x), next.y - Config.threshold*(next.y-now.y), next.z - Config.threshold*(next.z-now.z));
		now = next;
	    }
	}
        /*
	switch(direction)
	{
	    case UP:
		first.moveTo(first.x, first.y+Config.moveY, first.z);
		guideLineX.move(0, Config.moveY, 0);
		break;
	    case DOWN:
		first.moveTo(first.x, first.y-Config.moveY, first.z);
		guideLineX.move(0, -Config.moveY, 0);
		break;
	    case LEFT:
		first.moveTo(first.x-Config.moveX, first.y, first.z);
		guideLineY.move(-Config.moveX, 0, 0);
		break;
	    case RIGHT:
		first.moveTo(first.x+Config.moveX, first.y, first.z);
		guideLineY.move(Config.moveX, 0, 0);
		break;
	    case ASC:
		first.moveTo(first.x, first.y, first.z+Config.moveZ);
		guideLineY.move(0, 0, Config.moveZ);
		guideLineX.move(0, 0, Config.moveZ);
		break;
	    case DESC:
		first.moveTo(first.x, first.y, first.z-Config.moveZ);
		guideLineY.move(0, 0, -Config.moveZ);
		guideLineX.move(0, 0, -Config.moveZ);
		break;
	}
         * 
         */
        first.move(vx, vy, vz);
        
	if(debugger != null)
	{
	    debugger.update(debugger.T_Vic_Viper_X, first.x);
	    debugger.update(debugger.T_Vic_Viper_Y, first.y);
	    debugger.update(debugger.T_Vic_Viper_Z, first.z);
	}
    }
    public double[] getPosition()
    {
        MyPrimitive first = blocks.getLast(); //最後一個是頭
        double[] pos = new double[3];
        pos[0] = first.x;
        pos[1] = first.y;
        pos[2] = first.z;
        return pos;
    }
    static public int velToDir(double vx, double vy, double vz)
    {
        if(vx == 0 && vy == 0)
            return Snake.NONE;
        
        double angle = Math.atan2(vy, vx);
        
        if(angle < Math.PI/8 && angle >= -Math.PI/8)
            return Snake.RIGHT;
        else if(angle < Math.PI*3/8 && angle >= Math.PI/8)
            return Snake.UP_RIGHT;
        else if(angle < Math.PI*5/8 && angle >= Math.PI*3/8)
            return Snake.UP;
        else if(angle < Math.PI*7/8 && angle >= Math.PI*5/8)
            return Snake.UP_LEFT;
        else if(angle < -Math.PI*7/8 || angle >= Math.PI*7/8)
            return Snake.LEFT;
        else if(angle < -Math.PI*5/8 && angle >= -Math.PI*7/8)
            return Snake.DOWN_LEFT;
        else if(angle < -Math.PI*3/8 && angle >= -Math.PI*5/8)
            return Snake.DOWN;
        else if(angle < -Math.PI*1/8 && angle >= -Math.PI*3/8)
            return Snake.DOWN_RIGHT;
        
        return Snake.NONE;
    }
    public int velToDir()
    {
        return velToDir(vx, vy, vz);
    }
    public static double[] dirToVel(int direction)
    {
        switch(direction)
        {
            //移動
            case Snake.UP:
                return new double[] {0,Config.moveY,0};
            case Snake.DOWN:
                return new double[] {0,-Config.moveY,0};
            case Snake.LEFT:
                return new double[] {-Config.moveX,0,0};
            case Snake.RIGHT:
                return new double[] {Config.moveX,0,0};
            case Snake.UP_RIGHT:
                return new double[] {Config.moveX,Config.moveY,0};
            case Snake.UP_LEFT:
                return new double[] {-Config.moveX,Config.moveY,0};
            case Snake.DOWN_RIGHT:
                return new double[] {Config.moveX,-Config.moveY,0};
            case Snake.DOWN_LEFT:
                return new double[] {-Config.moveX,-Config.moveY,0};
        }
        return new double[] {0,0,0};
    }
    private boolean checkBounding(MyPrimitive first)
    {
        if(first.y > Config.boundingH)
        {
            if(Config.debug)
                System.out.println("超出Y上界");
            return true;
        }
        if(first.y < -Config.boundingH)
        {
            if(Config.debug)
                System.out.println("超出Y下界");
            return true;
        }
        if(first.x < -Config.boundingW)
        {
            if(Config.debug)
                System.out.println("超出X左界");
            return true;
        }
        if(first.x > Config.boundingW)
        {
            if(Config.debug)
                System.out.println("超出X右界");
            return true;
        }
        /*
        if(first.z > Config.blockD*Config.d)
        {
            if(Config.debug)
                System.out.println("超出z頂端");
            return true;
        }
        if(first.z < -Config.blockD*Config.d)
        {
            if(Config.debug)
                System.out.println("超出Z底端");
            return true;
        }
         */
	return false;
    }
    private Bullet checkBullet(MyPrimitive first, Bullets bullets)
    {
        Iterator it = bullets.bulletList.iterator();
        while(it.hasNext())
        {
            Bullet b = (Bullet)it.next();
            if(Math.sqrt((first.x-b.x)*(first.x-b.x) + (first.y-b.y)*(first.y-b.y) + (first.z-b.z)*(first.z-b.z)) < Config.hitRadius)
                return b;
        }
        return null;
    }
    private Capsule checkCapsule(MyPrimitive first,Capsules capsules)
    {
          Iterator it = capsules.inScreen.iterator();
          while(it.hasNext())
          {
                Capsule c = (Capsule)it.next();
                if(Math.sqrt((first.x-c.x)*(first.x-c.x) + (first.y-c.y)*(first.y-c.y) + (first.z-c.z)*(first.z-c.z)) < Config.hitRadius+Config.capsuleRadius)
                    return c;
          }
	  return null;
    }
    private boolean checkWall(MyPrimitive first,BlockWall wall)
    {
          double coordX1;
          double coordY1;
          double coordZ1;
          double coordX2;
          double coordY2;
          double coordZ2;

              coordX1 = (wall.hole[0][0]*2-1)*Config.blockW*Config.w/(Config.edgeLength+1);   //轉換成絕對座標
              coordY1 = (wall.hole[0][1]*2-1)*Config.blockH*Config.h/(Config.edgeLength+1);
              coordZ1 = (wall.hole[0][2]*2-1)*Config.blockD*Config.d/(Config.edgeLength+1);
              coordX2 = (wall.hole[1][0]*2+1)*Config.blockW*Config.w/(Config.edgeLength+1);
              coordY2 = (wall.hole[1][1]*2+1)*Config.blockH*Config.h/(Config.edgeLength+1);
              coordZ2 = (wall.hole[1][2]*2+1)*Config.blockD*Config.d/(Config.edgeLength+1);

              coordX1 += Config.hitRadius;     //縮小牆內範圍
              coordY1 += Config.hitRadius;
              coordZ1 += Config.hitRadius;
              coordX2 -= Config.hitRadius;
              coordY2 -= Config.hitRadius;
              coordZ2 -= Config.hitRadius;

          if(wall.normal == BlockWall.NORMAL_X)   //牆走x軸方向
            {
                  if(Math.abs(wall.x - first.x)<Config.hitRadius)
                  {
                        if(first.y>coordY1&&first.y<coordY2&&first.z>coordZ1&&first.z<coordZ2)
                              return false;
                        else
                              return true;
                  }
                  else
                        return false;
             }
            else if(wall.normal == BlockWall.NORMAL_Y)
            {
                  if(Math.abs(wall.y  - first.y)<Config.hitRadius)
                  {
                        if(first.x>coordX1&&first.x<coordX2&&first.z>coordZ1&&first.z<coordZ2)
                              return false;
                        else
                              return true;
                  }
                  else
                        return false;
            }
            else if(wall.normal == BlockWall.NORMAL_Z)
            {
                  if(Math.abs(wall.z - first.z)<Config.hitRadius)
                  {
                        if(first.x>coordX1&&first.x<coordX2&&first.y>coordY1&&first.y<coordY2)
                              return false;
                        else
                              return true;
                  }
                  else
                        return false;
            }
	    else
                  return false;
    }
}
